package com.yixin.hospital.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.yixin.hospital.common.ApiResult;
import com.yixin.hospital.entity.bo.PageInfo;
import com.yixin.hospital.entity.bo.TemplateDetail;
import com.yixin.hospital.entity.domain.Guidance;
import com.yixin.hospital.entity.domain.Template;
import com.yixin.hospital.entity.domain.VisitInspectionList;
import com.yixin.hospital.entity.dto.req.guidance.GuidanceAddReqDTO;
import com.yixin.hospital.entity.dto.req.visit.VisitStopReqDTO;
import com.yixin.hospital.entity.vo.GuidanceStatusReportsVo;
import com.yixin.hospital.entity.vo.GuidanceWaitingNumVO;
import com.yixin.hospital.entity.vo.ListGuidanceVO;
import com.yixin.hospital.enums.DrugVisitStatusEnum;
import com.yixin.hospital.enums.GuidanceStatusEnum;
import com.yixin.hospital.enums.GuidanceTypeEnum;
import com.yixin.hospital.mapper.GuidanceMapper;
import com.yixin.hospital.mapper.extend.GuidanceExtendMapper;
import com.yixin.hospital.service.GuidanceService;
import com.yixin.hospital.service.JobOfficeService;
import com.yixin.hospital.service.TemplateService;
import com.yixin.hospital.service.VisitInspectionListService;
import com.yixin.hospital.utils.DateUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.yixin.hospital.common.Constant.format;
import static com.yixin.hospital.enums.ResponseCodeEnum.NOT_FOUND_TEMPLATE;

/**
* @author Administrator
* @description 针对表【guidance(导诊表)】的数据库操作Service实现
* @createDate 2024-11-13 17:12:41
*/
@Service
public class GuidanceServiceImpl extends ServiceImpl<GuidanceMapper, Guidance>
    implements GuidanceService{

    @Resource
    private GuidanceExtendMapper guidanceExtendMapper;
    @Resource
    private TemplateService templateService;
    @Resource
    private JobOfficeService jobOfficeService;
    @Resource
    private VisitInspectionListService visitInspectionListService;


    @Override
    public ApiResult<PageInfo<ListGuidanceVO>> allList(int currentPage, int pageSize, String name, Long deptId, Long workAddressId, Long jobOfficeId, Integer status) {
        List<Integer> statusList = Objects.nonNull(status) ?  Arrays.asList(status) : new ArrayList<>();
        if (GuidanceStatusEnum.CHECKING.getCode().equals(status) || GuidanceStatusEnum.DRUG.getCode().equals(status)) statusList = Arrays.asList(status, GuidanceStatusEnum.CHECKING_DRUG.getCode());
        IPage<ListGuidanceVO> listGuidanceVOIPage = guidanceExtendMapper.pageVo(Page.of(currentPage, pageSize), name, deptId, workAddressId, jobOfficeId, statusList);
        PageInfo<ListGuidanceVO> listGuidanceVOPageInfo = new PageInfo<>();
        BeanUtils.copyProperties(listGuidanceVOIPage, listGuidanceVOPageInfo);

        for (ListGuidanceVO record : listGuidanceVOPageInfo.getRecords()) {
            record.setTypeName(GuidanceTypeEnum.getDesc(record.getType()));
            record.setTemplateDetailList(new Gson().fromJson(record.getDetail().toString(), new TypeToken<List<TemplateDetail>>() {}.getType()));
            Integer betweenMinute = (int) ChronoUnit.MINUTES.between(record.getGuidanceTime(), LocalDateTime.now());
            // 挂号后静止时间倒计时
            record.setRemainderTime(betweenMinute < record.getWaitTime() ? record.getWaitTime() - betweenMinute : 0);
            String afterGuidanceTime = DateUtil.toChineseDate(betweenMinute);
            // 挂号后至现在时长
            record.setAfterGuidanceTime(afterGuidanceTime);
            // 支付列表：支付等待时间
            if (GuidanceStatusEnum.PAYING.getCode().equals(status) && Objects.nonNull(record.getVisitTime()) || Objects.nonNull(record.getInspectionTime())) {
                Integer waitPayBetweenMinute = (int) ChronoUnit.MINUTES.between(Objects.nonNull(record.getVisitTime()) ? record.getVisitTime() : record.getInspectionTime(), LocalDateTime.now());
                record.setWaitPayTime(DateUtil.toChineseDate(waitPayBetweenMinute));
            }
            // 实验室列表：实验室检查付款后 至 现在时长：now - inspectionTime
            if (GuidanceStatusEnum.CHECKING.getCode().equals(status) && Objects.nonNull(record.getInspectionTime())) {
                Integer inspectionBetweenMinute = (int) ChronoUnit.MINUTES.between(record.getInspectionTime(), LocalDateTime.now());
                record.setWaitInspectionTime(DateUtil.toChineseDate(inspectionBetweenMinute));
                Integer count = 0;
                Integer doneInspectionCount = record.getDoneInspectionCount();
                if (doneInspectionCount.compareTo(0) != 0) count++;
                record.setInspectionCount(record.getPaidInspectionCount() + count);
            }
        }
        return ApiResult.success(listGuidanceVOPageInfo);
    }

    @Override
    public ApiResult<?> addOrUpdate(GuidanceAddReqDTO guidanceAddReqDTO, Long userId, String userName) {
        Guidance guidance = new Guidance();
        BeanUtils.copyProperties(guidanceAddReqDTO, guidance);
        guidance.setDoctorId(guidanceAddReqDTO.getDoctorId());
        guidance.setSubmitUserId(userId);
        guidance.setCreatedBy(userName);
        guidance.setUpdatedBy(userName);
        // add
        if (Objects.isNull(guidanceAddReqDTO.getId())) {
            LambdaQueryWrapper<Template> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Template::getJobOffice, guidanceAddReqDTO.getJobOfficeId());
            List<Template> templateList = templateService.list(queryWrapper);
            if (CollectionUtil.isEmpty(templateList)) return ApiResult.error(NOT_FOUND_TEMPLATE);
            Template template = templateList.get(0);
            guidance.setTemplateId(template.getId());
            guidance.setDetail(template.getDetail());
            guidance.setStatus(0);
            String code = "JZ" + LocalDateTime.now().format(DateTimeFormatter.ofPattern(format));
            guidance.setGuidanceCode(code);
            guidance.setGuidanceTime(LocalDateTime.now());
            this.save(guidance);
            return ApiResult.success();
        }
        // edit
        guidance.setIsDetail(1);
        guidance.setDetail(new Gson().toJson(guidanceAddReqDTO.getTemplateDetailList()));
        this.updateById(guidance);

        return ApiResult.success();
    }

    @Override
    public ApiResult<?> guidanceWaitingNumber(Long deptId, Long workAddressId, Long jobOfficeId) {
        // 候诊人数
        List<Guidance> waitingList = this.list(new QueryWrapper<Guidance>()
                .select("job_office_id as jobOfficeId, count(*) as waitingCount")
                .eq("status", GuidanceStatusEnum.WAITING.getCode())
                .eq("dept_id", deptId)
                .eq("work_address_id", workAddressId)
                .groupBy("job_office_id")

        );
//        Map<Long, Long> waitingMap = waitingList.isEmpty() ? new HashMap<>() : waitingList.stream().collect(Collectors.toMap(Guidance::getJobOfficeId, Guidance::getWaitingCount));

        // 就诊人数
        List<Guidance> doingList = this.list(new QueryWrapper<Guidance>()
                .select("job_office_id as jobOfficeId, count(*) as doingCount")
                .eq("status", GuidanceStatusEnum.VISITING.getCode())
                .eq("dept_id", deptId)
                .eq("work_address_id", workAddressId)
                .groupBy("job_office_id")

        );
//        Map<Long, Long> doingMap = doingList.isEmpty() ? new HashMap<>() : doingList.stream().collect(Collectors.toMap(Guidance::getJobOfficeId, Guidance::getDoingCount));

        List<GuidanceWaitingNumVO> guidanceWaitingNumVOList = new ArrayList<>();
//        for (Map.Entry<Long, Long> entry : waitingMap.entrySet()) {
//            GuidanceWaitingNumVO guidanceWaitingNumVO = new GuidanceWaitingNumVO();
//            Long key = entry.getKey();
//            guidanceWaitingNumVO.setJobOfficeId(key);
//            guidanceWaitingNumVO.setJobOfficeName(jobOfficeService.getById(key).getName());
//            guidanceWaitingNumVO.setWaitingCount(entry.getValue());
//            if (doingMap.containsKey(key)) {
//                guidanceWaitingNumVO.setDoingCount(doingMap.get(key));
//            }
//            guidanceWaitingNumVOList.add(guidanceWaitingNumVO);
//        }

        if (jobOfficeId != null && !guidanceWaitingNumVOList.isEmpty()) {
            List<GuidanceWaitingNumVO> collect = guidanceWaitingNumVOList.stream().filter(guidanceWaitingNumVO -> guidanceWaitingNumVO.getJobOfficeId().equals(jobOfficeId)).collect(Collectors.toList());
            return ApiResult.success(collect);
        }


        return ApiResult.success(guidanceWaitingNumVOList);
    }

    @Override
    public ApiResult<?> guidanceStop(VisitStopReqDTO visitStopReqDTO, String userName) {
        Guidance guidance = this.getOne(new LambdaQueryWrapper<Guidance>().eq(Guidance::getGuidanceCode, visitStopReqDTO.getGuidanceCode()));
        guidance.setStatus(GuidanceStatusEnum.SUSPEND.getCode());
        guidance.setRemark(visitStopReqDTO.getStopRemark());
        guidance.setUpdatedBy(userName);
        this.updateById(guidance);
        return ApiResult.success();
    }

    @Override
    public ApiResult<?> jobStatusList(Long deptId) {
        List<GuidanceStatusReportsVo> list = guidanceExtendMapper.statusReports(deptId);
        return ApiResult.success(list);
    }
}




